package concurrecy.lock2;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class JannaArrayBlockingQueue<T> {
    // 队列的大小
    private volatile int size;
    // 存放数据的数组
    private final Object[] data;

    // 存数据和取数据的指针
    private int putIndex, takeIndex;

    private Lock lock = new ReentrantLock();
    private Condition putCondition = lock.newCondition();
    private Condition takeCondition = lock.newCondition();

    public JannaArrayBlockingQueue(int capacity) {
        data = new Object[capacity];
    }

    /**
     * 放入队列中
     * @param t
     */
    public void put(T t) {
        lock.lock();
        try {
            // 队列已满
            while(size == data.length)
                putCondition.await();
            data[putIndex ++] = t;
            if(putIndex == data.length)
                putIndex = 0;
            size ++;
            takeCondition.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 从队列中取出
     * @return
     */
    public T take() {
        lock.lock();
        try {
            // 队列为空
            while(data.length == 0)
                takeCondition.await();
            T t = (T) data[takeIndex ++];
            if(takeIndex == data.length)
                takeIndex = 0;
            size --;
            putCondition.signal();
            return t;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return null;
    }
}

public class MyArrayBlockingQueueDemo {
    public static void main(String[] args) throws InterruptedException {
        JannaArrayBlockingQueue<String> blockingQueue = new JannaArrayBlockingQueue<>(5);
        new Thread(() -> {
            for (int i = 0; i < 20; i++) {
                String s = "s" + i;
                blockingQueue.put(s);
                System.out.println("put " + s);
            }
        }).start();

        for (int i = 0; i < 20; i++) {
            Thread.sleep(1000);
            System.out.println("take "+ blockingQueue.take());
        }
    }
}
